{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Replicate and Improve the visualization"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Accociated with the article [How to improve the visualization: a story with chart from medical paper](https://github.com/Lucifer-x/visualization-story-with-a-chart-from-medical-paper/blob/main/README.md)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Preparation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.1 Import packages which are needed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Using in the replication\n",
    "import matplotlib.pyplot as plt\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "# Using in the improvement\n",
    "from matplotlib.widgets import RadioButtons\n",
    "from matplotlib.gridspec import GridSpec\n",
    "from matplotlib.axes import Axes\n",
    "from copy import deepcopy\n",
    "from matplotlib import cm"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2 Define constant"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "SIZE = (13,5)\n",
    "PATH = 'data.csv'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.3 Load Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.read_csv(PATH,index_col=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Replication through matlibplot"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.1 Define the colors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "colors = dict(zip(df.columns,map(lambda x: '#{}'.format(x),['4474c6','ee7d31','a5a5a5','fbc00a','e24e4e','6fac45','274279','9e480b','626262','957401','266090'])))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2 Initial the plot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 936x360 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig,ax = plt.subplots(figsize=(13,5))\n",
    "# Show grids of the plot\n",
    "ax.grid(axis=\"y\")\n",
    "# Make the boder of plot invisible\n",
    "ax.spines['top'].set_visible(False)\n",
    "ax.spines['right'].set_visible(False)\n",
    "ax.spines['left'].set_visible(False)\n",
    "ax.tick_params(bottom=False, top=False, left=False, right=False)\n",
    "# Set the ticks of y-axis\n",
    "ys = [0,50,100,150,200,250]\n",
    "ax.set_yticks(ys)\n",
    "ax.set_ylim(0,250)\n",
    "# Set the tick of x-axis\n",
    "xs = df.index\n",
    "ax.set_xlim(-0.6,len(xs)-0.5)\n",
    "ax.set_xticks(np.arange(len(xs)))\n",
    "ax.set_xticklabels(xs,minor=True)\n",
    "None"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.3 Draw the plot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "heights = np.zeros(len(df.index))\n",
    "# Reorder the columns of data\n",
    "cols = ['hematopoietic system disease','immune system disease','arterial pressure nos decreased','dizziness','respiratory system disease', 'cancer','integumentary system disease','urinary system disease','headache','cardiovascular system disease','viral infectious disease']\n",
    "# Draw the stacked bar plot\n",
    "for y in cols:\n",
    "    ax.bar(df[y].index,df[y].values,bottom=heights,color=colors[y],width=0.5,label=y)\n",
    "    heights += df[y].values\n",
    "# Draw the legend of plot\n",
    "ax.legend(loc='lower center',ncol=4,frameon=False,bbox_to_anchor=(0.5,-0.3),handlelength=0.5)\n",
    "None"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "### 2.4 Show the result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 936x360 with 1 Axes>"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fig"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Improvement"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.1 Preparation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib notebook\n",
    "%matplotlib notebook"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "from components import SelectionBox,SelectionPlot"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2 Creating module"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We have created a module _components.py_ to realize the creation of the visualization. The module file concludes two classes and the code is shown below:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3.2.1 SelectionBox"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "class SelectionBox(RadioButtons):\n",
    "    \"\"\"\n",
    "    This is a custom class inherited from the \"matplotlib.widgets.RadioButtons\".\n",
    "\n",
    "    For the buttons to remain responsive you must keep a reference to this\n",
    "    object.\n",
    "\n",
    "    Connect to the SelectionBox with the `.on_clicked` method.\n",
    "\n",
    "    Attributes\n",
    "    ----------\n",
    "    ax : `matplotlib.axes.Axes`\n",
    "        The parent axes for the widget.\n",
    "    activecolor : color\n",
    "        The color of the selected button.\n",
    "    labels : list of `.Text`\n",
    "        The button labels.\n",
    "    circles : list of `~.patches.Circle`\n",
    "        The buttons.\n",
    "    value_selected : str\n",
    "        The label text of the currently selected button.\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(self, ax: Axes, **params):\n",
    "        \"\"\"\n",
    "        Add selection box an `matplotlib.axes.Axes`.\n",
    "\n",
    "        Parameters\n",
    "        ----------\n",
    "        ax : `matplotlib.axes.Axes`\n",
    "            The axes to add the buttons to.\n",
    "        labels : list of str\n",
    "            The button labels.\n",
    "        active : int\n",
    "            The index of the initially selected button.\n",
    "        activecolor : color\n",
    "            The color of the selected button.\n",
    "        \"\"\"\n",
    "        self.ax = ax\n",
    "        self.ax.clear()\n",
    "        for spine in self.ax.spines:\n",
    "            self.ax.spines[spine].set_visible(False)\n",
    "        self.ax.set(aspect='equal')\n",
    "        super().__init__(ax, **params)\n",
    "\n",
    "    def set_buttons(self, radius: float = 0.02, offset: float = 0.06, circleprops: dict = None, textprops: dict = None):\n",
    "        \"\"\"\n",
    "        Set the style of buttons.\n",
    "\n",
    "        Parameters\n",
    "        ----------\n",
    "        radius: float\n",
    "            The radius of buttons.\n",
    "        offset: float\n",
    "            The offset between bottom and labels.\n",
    "        circleprops : dict, optional\n",
    "            The properties of the style of each button's circle.\n",
    "        textprops : dict, optional\n",
    "            The properties of the style of each button's label.\n",
    "        \"\"\"\n",
    "        if circleprops is None:\n",
    "            circleprops = {}\n",
    "        if textprops is None:\n",
    "            textprops = {}\n",
    "        for circle, label in zip(self.circles, self.labels):\n",
    "            x, y = circle.get_center()\n",
    "            circle.set_radius(radius)\n",
    "            circle.set_center((x + offset, y))\n",
    "            circle.set(**circleprops)\n",
    "            label.set(**textprops)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3.2.2 SelectionBox"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "class SelectionPlot:\n",
    "    \"\"\"\n",
    "    This is a custom class which is to create bar charts and pie charts\n",
    "    according to the options of ratio buttons.\n",
    "\n",
    "    Reffered to the options selected by the user, the class create the plot\n",
    "    based on the corresponding data.\n",
    "\n",
    "    Attributes\n",
    "    ----------\n",
    "    ax : `matplotlib.axes.Axes`\n",
    "        The parent axes for the plot.\n",
    "    \"\"\"\n",
    "\n",
    "    def __init__(self, ax: Axes,\n",
    "                 labels: pd.Series,\n",
    "                 data: pd.DataFrame,\n",
    "                 is_pie: bool = True,\n",
    "                 title: str = '{}',\n",
    "                 font_dicts: dict = None,\n",
    "                 **params):\n",
    "        \"\"\"\n",
    "\n",
    "        Parameters\n",
    "        ----------\n",
    "        ax : `matplotlib.axes.Axes`\n",
    "            The axes to add the plot to.\n",
    "        labels : `pd.Series`\n",
    "            The label of plot.\n",
    "        data : `pd.DataFrame`\n",
    "            The data of plot.\n",
    "        is_pie : bool\n",
    "            If true, draw the pie plot, else draw the bar plot.\n",
    "        title : str\n",
    "            Title of plot.\n",
    "        font_dicts: dict\n",
    "            The dictionary of font style.\n",
    "            ==========   ======================================================\n",
    "            Key          Description\n",
    "            ==========   ======================================================\n",
    "            global      The style of all the fonts\n",
    "            title       The style of title\n",
    "            label       The style of label\n",
    "            value       The style of value\n",
    "            ==========   ======================================================\n",
    "        **params :\n",
    "            The parameters of the plot.\n",
    "        \"\"\"\n",
    "        if not font_dicts:\n",
    "            font_dicts = {'global': {'family': 'Times New Roman'},\n",
    "                          'title': {'weight': 'black', 'size': 14},\n",
    "                          'label': {},\n",
    "                          'value': {}}\n",
    "        self.ax = ax\n",
    "        self.__labels = labels\n",
    "        self.__data = data\n",
    "        self.__is_pie = is_pie\n",
    "        self.__title = title\n",
    "        self.__params = params\n",
    "        self.__font_dicts = font_dicts\n",
    "        self.__rc = rc('font', **self.__font_dicts['global'])\n",
    "        self.__init_plot()\n",
    "\n",
    "    def __init_plot(self):\n",
    "        \"\"\"\n",
    "        Initialize the plot, setting x_axis if the type of graph is bar chart.\n",
    "        \"\"\"\n",
    "        # Make the border of plot invisible\n",
    "        for position in self.ax.spines:\n",
    "            if not self.__is_pie and position == \"bottom\":\n",
    "                continue\n",
    "            self.ax.spines[position].set_visible(False)\n",
    "        # Init the plot\n",
    "        self.draw('all')\n",
    "\n",
    "    def draw(self, value):\n",
    "        \"\"\"\n",
    "        Creating corresponding plot based on the option of the radio button.\n",
    "\n",
    "        Parameters\n",
    "        ----------\n",
    "        value : str\n",
    "            The label text of the currently selected button.\n",
    "        \"\"\"\n",
    "        self.ax.clear()\n",
    "        self.ax.set_title(self.__title.format(value + ' drugs' if value == 'all' else value),\n",
    "                          fontdict=self.__font_dicts['title'])\n",
    "\n",
    "        # Draw the pie plot\n",
    "        if self.__is_pie:\n",
    "            # Set y-axis\n",
    "            self.ax.set_yticks([])\n",
    "            pctdistance = 1.09 if value == 'all' else 0.6\n",
    "            labeldistance = 1.2 if value == 'all' else 1.1\n",
    "            pie = self.ax.pie(x=self.__data.loc[value][self.__data.loc[value] != 0],\n",
    "                              labels=self.__data.loc[value][self.__data.loc[value] != 0].index,\n",
    "                              autopct='%1.0f%%',\n",
    "                              pctdistance=pctdistance,\n",
    "                              labeldistance=labeldistance,\n",
    "                              **self.__params)\n",
    "            for label, value in zip(pie[1], pie[2]):\n",
    "                label.set(**self.__font_dicts['label'])\n",
    "                value.set(**self.__font_dicts['value'])\n",
    "\n",
    "        # Draw the bar plot\n",
    "        else:\n",
    "            # Set y-axis\n",
    "            max_value = max(self.__data[filter(lambda x: x != 'all', self.__data.columns)].max()) \\\n",
    "                if value != 'all' \\\n",
    "                else max(self.__data[value])\n",
    "            self.ax.set_ylim(0, max_value * 1.1)\n",
    "            # Set x-axis\n",
    "            self.ax.set_xlim(-0.6, len(self.__labels) - 0.5)\n",
    "            self.ax.tick_params(bottom=False, top=False, left=False, right=False)\n",
    "            self.ax.set_xticklabels(self.__labels,\n",
    "                                    fontdict=self.__font_dicts['label'])\n",
    "            # Draw the bar plot\n",
    "            rects = self.ax.bar(x=self.__labels,\n",
    "                                height=self.__data[value],\n",
    "                                **self.__params)\n",
    "            # Add value on the top of each bar\n",
    "            for rect in rects:\n",
    "                height = rect.get_height()\n",
    "                if height:\n",
    "                    self.ax.annotate('{}'.format(height),\n",
    "                                     xy=(rect.get_x() + rect.get_width() / 2, height),\n",
    "                                     xytext=(0, 1),\n",
    "                                     textcoords=\"offset points\",\n",
    "                                     ha='center',\n",
    "                                     va='bottom',\n",
    "                                     **self.__font_dicts['value'])\n",
    "        return self.ax\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.3 Reformat data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "pie_data = deepcopy(df)\n",
    "sum_ = df.sum(axis=0)\n",
    "sum_.name = 'all'\n",
    "pie_data = pie_data.append(sum_)\n",
    "pie_labels = pie_data.index\n",
    "bar_data = deepcopy(df)\n",
    "bar_data['all'] = df.sum(axis=1)\n",
    "bar_labels = bar_data.index"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.4 Draw the plot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "/* Put everything inside the global mpl namespace */\n",
       "window.mpl = {};\n",
       "\n",
       "\n",
       "mpl.get_websocket_type = function() {\n",
       "    if (typeof(WebSocket) !== 'undefined') {\n",
       "        return WebSocket;\n",
       "    } else if (typeof(MozWebSocket) !== 'undefined') {\n",
       "        return MozWebSocket;\n",
       "    } else {\n",
       "        alert('Your browser does not have WebSocket support. ' +\n",
       "              'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
       "              'Firefox 4 and 5 are also supported but you ' +\n",
       "              'have to enable WebSockets in about:config.');\n",
       "    };\n",
       "}\n",
       "\n",
       "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
       "    this.id = figure_id;\n",
       "\n",
       "    this.ws = websocket;\n",
       "\n",
       "    this.supports_binary = (this.ws.binaryType != undefined);\n",
       "\n",
       "    if (!this.supports_binary) {\n",
       "        var warnings = document.getElementById(\"mpl-warnings\");\n",
       "        if (warnings) {\n",
       "            warnings.style.display = 'block';\n",
       "            warnings.textContent = (\n",
       "                \"This browser does not support binary websocket messages. \" +\n",
       "                    \"Performance may be slow.\");\n",
       "        }\n",
       "    }\n",
       "\n",
       "    this.imageObj = new Image();\n",
       "\n",
       "    this.context = undefined;\n",
       "    this.message = undefined;\n",
       "    this.canvas = undefined;\n",
       "    this.rubberband_canvas = undefined;\n",
       "    this.rubberband_context = undefined;\n",
       "    this.format_dropdown = undefined;\n",
       "\n",
       "    this.image_mode = 'full';\n",
       "\n",
       "    this.root = $('<div/>');\n",
       "    this._root_extra_style(this.root)\n",
       "    this.root.attr('style', 'display: inline-block');\n",
       "\n",
       "    $(parent_element).append(this.root);\n",
       "\n",
       "    this._init_header(this);\n",
       "    this._init_canvas(this);\n",
       "    this._init_toolbar(this);\n",
       "\n",
       "    var fig = this;\n",
       "\n",
       "    this.waiting = false;\n",
       "\n",
       "    this.ws.onopen =  function () {\n",
       "            fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
       "            fig.send_message(\"send_image_mode\", {});\n",
       "            if (mpl.ratio != 1) {\n",
       "                fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
       "            }\n",
       "            fig.send_message(\"refresh\", {});\n",
       "        }\n",
       "\n",
       "    this.imageObj.onload = function() {\n",
       "            if (fig.image_mode == 'full') {\n",
       "                // Full images could contain transparency (where diff images\n",
       "                // almost always do), so we need to clear the canvas so that\n",
       "                // there is no ghosting.\n",
       "                fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
       "            }\n",
       "            fig.context.drawImage(fig.imageObj, 0, 0);\n",
       "        };\n",
       "\n",
       "    this.imageObj.onunload = function() {\n",
       "        fig.ws.close();\n",
       "    }\n",
       "\n",
       "    this.ws.onmessage = this._make_on_message_function(this);\n",
       "\n",
       "    this.ondownload = ondownload;\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._init_header = function() {\n",
       "    var titlebar = $(\n",
       "        '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
       "        'ui-helper-clearfix\"/>');\n",
       "    var titletext = $(\n",
       "        '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
       "        'text-align: center; padding: 3px;\"/>');\n",
       "    titlebar.append(titletext)\n",
       "    this.root.append(titlebar);\n",
       "    this.header = titletext[0];\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
       "\n",
       "}\n",
       "\n",
       "\n",
       "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
       "\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._init_canvas = function() {\n",
       "    var fig = this;\n",
       "\n",
       "    var canvas_div = $('<div/>');\n",
       "\n",
       "    canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
       "\n",
       "    function canvas_keyboard_event(event) {\n",
       "        return fig.key_event(event, event['data']);\n",
       "    }\n",
       "\n",
       "    canvas_div.keydown('key_press', canvas_keyboard_event);\n",
       "    canvas_div.keyup('key_release', canvas_keyboard_event);\n",
       "    this.canvas_div = canvas_div\n",
       "    this._canvas_extra_style(canvas_div)\n",
       "    this.root.append(canvas_div);\n",
       "\n",
       "    var canvas = $('<canvas/>');\n",
       "    canvas.addClass('mpl-canvas');\n",
       "    canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
       "\n",
       "    this.canvas = canvas[0];\n",
       "    this.context = canvas[0].getContext(\"2d\");\n",
       "\n",
       "    var backingStore = this.context.backingStorePixelRatio ||\n",
       "\tthis.context.webkitBackingStorePixelRatio ||\n",
       "\tthis.context.mozBackingStorePixelRatio ||\n",
       "\tthis.context.msBackingStorePixelRatio ||\n",
       "\tthis.context.oBackingStorePixelRatio ||\n",
       "\tthis.context.backingStorePixelRatio || 1;\n",
       "\n",
       "    mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
       "\n",
       "    var rubberband = $('<canvas/>');\n",
       "    rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
       "\n",
       "    var pass_mouse_events = true;\n",
       "\n",
       "    canvas_div.resizable({\n",
       "        start: function(event, ui) {\n",
       "            pass_mouse_events = false;\n",
       "        },\n",
       "        resize: function(event, ui) {\n",
       "            fig.request_resize(ui.size.width, ui.size.height);\n",
       "        },\n",
       "        stop: function(event, ui) {\n",
       "            pass_mouse_events = true;\n",
       "            fig.request_resize(ui.size.width, ui.size.height);\n",
       "        },\n",
       "    });\n",
       "\n",
       "    function mouse_event_fn(event) {\n",
       "        if (pass_mouse_events)\n",
       "            return fig.mouse_event(event, event['data']);\n",
       "    }\n",
       "\n",
       "    rubberband.mousedown('button_press', mouse_event_fn);\n",
       "    rubberband.mouseup('button_release', mouse_event_fn);\n",
       "    // Throttle sequential mouse events to 1 every 20ms.\n",
       "    rubberband.mousemove('motion_notify', mouse_event_fn);\n",
       "\n",
       "    rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
       "    rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
       "\n",
       "    canvas_div.on(\"wheel\", function (event) {\n",
       "        event = event.originalEvent;\n",
       "        event['data'] = 'scroll'\n",
       "        if (event.deltaY < 0) {\n",
       "            event.step = 1;\n",
       "        } else {\n",
       "            event.step = -1;\n",
       "        }\n",
       "        mouse_event_fn(event);\n",
       "    });\n",
       "\n",
       "    canvas_div.append(canvas);\n",
       "    canvas_div.append(rubberband);\n",
       "\n",
       "    this.rubberband = rubberband;\n",
       "    this.rubberband_canvas = rubberband[0];\n",
       "    this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
       "    this.rubberband_context.strokeStyle = \"#000000\";\n",
       "\n",
       "    this._resize_canvas = function(width, height) {\n",
       "        // Keep the size of the canvas, canvas container, and rubber band\n",
       "        // canvas in synch.\n",
       "        canvas_div.css('width', width)\n",
       "        canvas_div.css('height', height)\n",
       "\n",
       "        canvas.attr('width', width * mpl.ratio);\n",
       "        canvas.attr('height', height * mpl.ratio);\n",
       "        canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
       "\n",
       "        rubberband.attr('width', width);\n",
       "        rubberband.attr('height', height);\n",
       "    }\n",
       "\n",
       "    // Set the figure to an initial 600x600px, this will subsequently be updated\n",
       "    // upon first draw.\n",
       "    this._resize_canvas(600, 600);\n",
       "\n",
       "    // Disable right mouse context menu.\n",
       "    $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
       "        return false;\n",
       "    });\n",
       "\n",
       "    function set_focus () {\n",
       "        canvas.focus();\n",
       "        canvas_div.focus();\n",
       "    }\n",
       "\n",
       "    window.setTimeout(set_focus, 100);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._init_toolbar = function() {\n",
       "    var fig = this;\n",
       "\n",
       "    var nav_element = $('<div/>');\n",
       "    nav_element.attr('style', 'width: 100%');\n",
       "    this.root.append(nav_element);\n",
       "\n",
       "    // Define a callback function for later on.\n",
       "    function toolbar_event(event) {\n",
       "        return fig.toolbar_button_onclick(event['data']);\n",
       "    }\n",
       "    function toolbar_mouse_event(event) {\n",
       "        return fig.toolbar_button_onmouseover(event['data']);\n",
       "    }\n",
       "\n",
       "    for(var toolbar_ind in mpl.toolbar_items) {\n",
       "        var name = mpl.toolbar_items[toolbar_ind][0];\n",
       "        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
       "        var image = mpl.toolbar_items[toolbar_ind][2];\n",
       "        var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
       "\n",
       "        if (!name) {\n",
       "            // put a spacer in here.\n",
       "            continue;\n",
       "        }\n",
       "        var button = $('<button/>');\n",
       "        button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
       "                        'ui-button-icon-only');\n",
       "        button.attr('role', 'button');\n",
       "        button.attr('aria-disabled', 'false');\n",
       "        button.click(method_name, toolbar_event);\n",
       "        button.mouseover(tooltip, toolbar_mouse_event);\n",
       "\n",
       "        var icon_img = $('<span/>');\n",
       "        icon_img.addClass('ui-button-icon-primary ui-icon');\n",
       "        icon_img.addClass(image);\n",
       "        icon_img.addClass('ui-corner-all');\n",
       "\n",
       "        var tooltip_span = $('<span/>');\n",
       "        tooltip_span.addClass('ui-button-text');\n",
       "        tooltip_span.html(tooltip);\n",
       "\n",
       "        button.append(icon_img);\n",
       "        button.append(tooltip_span);\n",
       "\n",
       "        nav_element.append(button);\n",
       "    }\n",
       "\n",
       "    var fmt_picker_span = $('<span/>');\n",
       "\n",
       "    var fmt_picker = $('<select/>');\n",
       "    fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
       "    fmt_picker_span.append(fmt_picker);\n",
       "    nav_element.append(fmt_picker_span);\n",
       "    this.format_dropdown = fmt_picker[0];\n",
       "\n",
       "    for (var ind in mpl.extensions) {\n",
       "        var fmt = mpl.extensions[ind];\n",
       "        var option = $(\n",
       "            '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
       "        fmt_picker.append(option);\n",
       "    }\n",
       "\n",
       "    // Add hover states to the ui-buttons\n",
       "    $( \".ui-button\" ).hover(\n",
       "        function() { $(this).addClass(\"ui-state-hover\");},\n",
       "        function() { $(this).removeClass(\"ui-state-hover\");}\n",
       "    );\n",
       "\n",
       "    var status_bar = $('<span class=\"mpl-message\"/>');\n",
       "    nav_element.append(status_bar);\n",
       "    this.message = status_bar[0];\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
       "    // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
       "    // which will in turn request a refresh of the image.\n",
       "    this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.send_message = function(type, properties) {\n",
       "    properties['type'] = type;\n",
       "    properties['figure_id'] = this.id;\n",
       "    this.ws.send(JSON.stringify(properties));\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.send_draw_message = function() {\n",
       "    if (!this.waiting) {\n",
       "        this.waiting = true;\n",
       "        this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
       "    var format_dropdown = fig.format_dropdown;\n",
       "    var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
       "    fig.ondownload(fig, format);\n",
       "}\n",
       "\n",
       "\n",
       "mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
       "    var size = msg['size'];\n",
       "    if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
       "        fig._resize_canvas(size[0], size[1]);\n",
       "        fig.send_message(\"refresh\", {});\n",
       "    };\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
       "    var x0 = msg['x0'] / mpl.ratio;\n",
       "    var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
       "    var x1 = msg['x1'] / mpl.ratio;\n",
       "    var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
       "    x0 = Math.floor(x0) + 0.5;\n",
       "    y0 = Math.floor(y0) + 0.5;\n",
       "    x1 = Math.floor(x1) + 0.5;\n",
       "    y1 = Math.floor(y1) + 0.5;\n",
       "    var min_x = Math.min(x0, x1);\n",
       "    var min_y = Math.min(y0, y1);\n",
       "    var width = Math.abs(x1 - x0);\n",
       "    var height = Math.abs(y1 - y0);\n",
       "\n",
       "    fig.rubberband_context.clearRect(\n",
       "        0, 0, fig.canvas.width / mpl.ratio, fig.canvas.height / mpl.ratio);\n",
       "\n",
       "    fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
       "    // Updates the figure title.\n",
       "    fig.header.textContent = msg['label'];\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
       "    var cursor = msg['cursor'];\n",
       "    switch(cursor)\n",
       "    {\n",
       "    case 0:\n",
       "        cursor = 'pointer';\n",
       "        break;\n",
       "    case 1:\n",
       "        cursor = 'default';\n",
       "        break;\n",
       "    case 2:\n",
       "        cursor = 'crosshair';\n",
       "        break;\n",
       "    case 3:\n",
       "        cursor = 'move';\n",
       "        break;\n",
       "    }\n",
       "    fig.rubberband_canvas.style.cursor = cursor;\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_message = function(fig, msg) {\n",
       "    fig.message.textContent = msg['message'];\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
       "    // Request the server to send over a new figure.\n",
       "    fig.send_draw_message();\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
       "    fig.image_mode = msg['mode'];\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.updated_canvas_event = function() {\n",
       "    // Called whenever the canvas gets updated.\n",
       "    this.send_message(\"ack\", {});\n",
       "}\n",
       "\n",
       "// A function to construct a web socket function for onmessage handling.\n",
       "// Called in the figure constructor.\n",
       "mpl.figure.prototype._make_on_message_function = function(fig) {\n",
       "    return function socket_on_message(evt) {\n",
       "        if (evt.data instanceof Blob) {\n",
       "            /* FIXME: We get \"Resource interpreted as Image but\n",
       "             * transferred with MIME type text/plain:\" errors on\n",
       "             * Chrome.  But how to set the MIME type?  It doesn't seem\n",
       "             * to be part of the websocket stream */\n",
       "            evt.data.type = \"image/png\";\n",
       "\n",
       "            /* Free the memory for the previous frames */\n",
       "            if (fig.imageObj.src) {\n",
       "                (window.URL || window.webkitURL).revokeObjectURL(\n",
       "                    fig.imageObj.src);\n",
       "            }\n",
       "\n",
       "            fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
       "                evt.data);\n",
       "            fig.updated_canvas_event();\n",
       "            fig.waiting = false;\n",
       "            return;\n",
       "        }\n",
       "        else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
       "            fig.imageObj.src = evt.data;\n",
       "            fig.updated_canvas_event();\n",
       "            fig.waiting = false;\n",
       "            return;\n",
       "        }\n",
       "\n",
       "        var msg = JSON.parse(evt.data);\n",
       "        var msg_type = msg['type'];\n",
       "\n",
       "        // Call the  \"handle_{type}\" callback, which takes\n",
       "        // the figure and JSON message as its only arguments.\n",
       "        try {\n",
       "            var callback = fig[\"handle_\" + msg_type];\n",
       "        } catch (e) {\n",
       "            console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
       "            return;\n",
       "        }\n",
       "\n",
       "        if (callback) {\n",
       "            try {\n",
       "                // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
       "                callback(fig, msg);\n",
       "            } catch (e) {\n",
       "                console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
       "            }\n",
       "        }\n",
       "    };\n",
       "}\n",
       "\n",
       "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
       "mpl.findpos = function(e) {\n",
       "    //this section is from http://www.quirksmode.org/js/events_properties.html\n",
       "    var targ;\n",
       "    if (!e)\n",
       "        e = window.event;\n",
       "    if (e.target)\n",
       "        targ = e.target;\n",
       "    else if (e.srcElement)\n",
       "        targ = e.srcElement;\n",
       "    if (targ.nodeType == 3) // defeat Safari bug\n",
       "        targ = targ.parentNode;\n",
       "\n",
       "    // jQuery normalizes the pageX and pageY\n",
       "    // pageX,Y are the mouse positions relative to the document\n",
       "    // offset() returns the position of the element relative to the document\n",
       "    var x = e.pageX - $(targ).offset().left;\n",
       "    var y = e.pageY - $(targ).offset().top;\n",
       "\n",
       "    return {\"x\": x, \"y\": y};\n",
       "};\n",
       "\n",
       "/*\n",
       " * return a copy of an object with only non-object keys\n",
       " * we need this to avoid circular references\n",
       " * http://stackoverflow.com/a/24161582/3208463\n",
       " */\n",
       "function simpleKeys (original) {\n",
       "  return Object.keys(original).reduce(function (obj, key) {\n",
       "    if (typeof original[key] !== 'object')\n",
       "        obj[key] = original[key]\n",
       "    return obj;\n",
       "  }, {});\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.mouse_event = function(event, name) {\n",
       "    var canvas_pos = mpl.findpos(event)\n",
       "\n",
       "    if (name === 'button_press')\n",
       "    {\n",
       "        this.canvas.focus();\n",
       "        this.canvas_div.focus();\n",
       "    }\n",
       "\n",
       "    var x = canvas_pos.x * mpl.ratio;\n",
       "    var y = canvas_pos.y * mpl.ratio;\n",
       "\n",
       "    this.send_message(name, {x: x, y: y, button: event.button,\n",
       "                             step: event.step,\n",
       "                             guiEvent: simpleKeys(event)});\n",
       "\n",
       "    /* This prevents the web browser from automatically changing to\n",
       "     * the text insertion cursor when the button is pressed.  We want\n",
       "     * to control all of the cursor setting manually through the\n",
       "     * 'cursor' event from matplotlib */\n",
       "    event.preventDefault();\n",
       "    return false;\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
       "    // Handle any extra behaviour associated with a key event\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.key_event = function(event, name) {\n",
       "\n",
       "    // Prevent repeat events\n",
       "    if (name == 'key_press')\n",
       "    {\n",
       "        if (event.which === this._key)\n",
       "            return;\n",
       "        else\n",
       "            this._key = event.which;\n",
       "    }\n",
       "    if (name == 'key_release')\n",
       "        this._key = null;\n",
       "\n",
       "    var value = '';\n",
       "    if (event.ctrlKey && event.which != 17)\n",
       "        value += \"ctrl+\";\n",
       "    if (event.altKey && event.which != 18)\n",
       "        value += \"alt+\";\n",
       "    if (event.shiftKey && event.which != 16)\n",
       "        value += \"shift+\";\n",
       "\n",
       "    value += 'k';\n",
       "    value += event.which.toString();\n",
       "\n",
       "    this._key_event_extra(event, name);\n",
       "\n",
       "    this.send_message(name, {key: value,\n",
       "                             guiEvent: simpleKeys(event)});\n",
       "    return false;\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
       "    if (name == 'download') {\n",
       "        this.handle_save(this, null);\n",
       "    } else {\n",
       "        this.send_message(\"toolbar_button\", {name: name});\n",
       "    }\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
       "    this.message.textContent = tooltip;\n",
       "};\n",
       "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
       "\n",
       "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
       "\n",
       "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
       "    // Create a \"websocket\"-like object which calls the given IPython comm\n",
       "    // object with the appropriate methods. Currently this is a non binary\n",
       "    // socket, so there is still some room for performance tuning.\n",
       "    var ws = {};\n",
       "\n",
       "    ws.close = function() {\n",
       "        comm.close()\n",
       "    };\n",
       "    ws.send = function(m) {\n",
       "        //console.log('sending', m);\n",
       "        comm.send(m);\n",
       "    };\n",
       "    // Register the callback with on_msg.\n",
       "    comm.on_msg(function(msg) {\n",
       "        //console.log('receiving', msg['content']['data'], msg);\n",
       "        // Pass the mpl event to the overridden (by mpl) onmessage function.\n",
       "        ws.onmessage(msg['content']['data'])\n",
       "    });\n",
       "    return ws;\n",
       "}\n",
       "\n",
       "mpl.mpl_figure_comm = function(comm, msg) {\n",
       "    // This is the function which gets called when the mpl process\n",
       "    // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
       "\n",
       "    var id = msg.content.data.id;\n",
       "    // Get hold of the div created by the display call when the Comm\n",
       "    // socket was opened in Python.\n",
       "    var element = $(\"#\" + id);\n",
       "    var ws_proxy = comm_websocket_adapter(comm)\n",
       "\n",
       "    function ondownload(figure, format) {\n",
       "        window.open(figure.imageObj.src);\n",
       "    }\n",
       "\n",
       "    var fig = new mpl.figure(id, ws_proxy,\n",
       "                           ondownload,\n",
       "                           element.get(0));\n",
       "\n",
       "    // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
       "    // web socket which is closed, not our websocket->open comm proxy.\n",
       "    ws_proxy.onopen();\n",
       "\n",
       "    fig.parent_element = element.get(0);\n",
       "    fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
       "    if (!fig.cell_info) {\n",
       "        console.error(\"Failed to find cell for figure\", id, fig);\n",
       "        return;\n",
       "    }\n",
       "\n",
       "    var output_index = fig.cell_info[2]\n",
       "    var cell = fig.cell_info[0];\n",
       "\n",
       "};\n",
       "\n",
       "mpl.figure.prototype.handle_close = function(fig, msg) {\n",
       "    var width = fig.canvas.width/mpl.ratio\n",
       "    fig.root.unbind('remove')\n",
       "\n",
       "    // Update the output cell to use the data from the current canvas.\n",
       "    fig.push_to_output();\n",
       "    var dataURL = fig.canvas.toDataURL();\n",
       "    // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
       "    // the notebook keyboard shortcuts fail.\n",
       "    IPython.keyboard_manager.enable()\n",
       "    $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n",
       "    fig.close_ws(fig, msg);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.close_ws = function(fig, msg){\n",
       "    fig.send_message('closing', msg);\n",
       "    // fig.ws.close()\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
       "    // Turn the data on the canvas into data in the output cell.\n",
       "    var width = this.canvas.width/mpl.ratio\n",
       "    var dataURL = this.canvas.toDataURL();\n",
       "    this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.updated_canvas_event = function() {\n",
       "    // Tell IPython that the notebook contents must change.\n",
       "    IPython.notebook.set_dirty(true);\n",
       "    this.send_message(\"ack\", {});\n",
       "    var fig = this;\n",
       "    // Wait a second, then push the new image to the DOM so\n",
       "    // that it is saved nicely (might be nice to debounce this).\n",
       "    setTimeout(function () { fig.push_to_output() }, 1000);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._init_toolbar = function() {\n",
       "    var fig = this;\n",
       "\n",
       "    var nav_element = $('<div/>');\n",
       "    nav_element.attr('style', 'width: 100%');\n",
       "    this.root.append(nav_element);\n",
       "\n",
       "    // Define a callback function for later on.\n",
       "    function toolbar_event(event) {\n",
       "        return fig.toolbar_button_onclick(event['data']);\n",
       "    }\n",
       "    function toolbar_mouse_event(event) {\n",
       "        return fig.toolbar_button_onmouseover(event['data']);\n",
       "    }\n",
       "\n",
       "    for(var toolbar_ind in mpl.toolbar_items){\n",
       "        var name = mpl.toolbar_items[toolbar_ind][0];\n",
       "        var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
       "        var image = mpl.toolbar_items[toolbar_ind][2];\n",
       "        var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
       "\n",
       "        if (!name) { continue; };\n",
       "\n",
       "        var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
       "        button.click(method_name, toolbar_event);\n",
       "        button.mouseover(tooltip, toolbar_mouse_event);\n",
       "        nav_element.append(button);\n",
       "    }\n",
       "\n",
       "    // Add the status bar.\n",
       "    var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
       "    nav_element.append(status_bar);\n",
       "    this.message = status_bar[0];\n",
       "\n",
       "    // Add the close button to the window.\n",
       "    var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
       "    var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
       "    button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
       "    button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
       "    buttongrp.append(button);\n",
       "    var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
       "    titlebar.prepend(buttongrp);\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._root_extra_style = function(el){\n",
       "    var fig = this\n",
       "    el.on(\"remove\", function(){\n",
       "\tfig.close_ws(fig, {});\n",
       "    });\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._canvas_extra_style = function(el){\n",
       "    // this is important to make the div 'focusable\n",
       "    el.attr('tabindex', 0)\n",
       "    // reach out to IPython and tell the keyboard manager to turn it's self\n",
       "    // off when our div gets focus\n",
       "\n",
       "    // location in version 3\n",
       "    if (IPython.notebook.keyboard_manager) {\n",
       "        IPython.notebook.keyboard_manager.register_events(el);\n",
       "    }\n",
       "    else {\n",
       "        // location in version 2\n",
       "        IPython.keyboard_manager.register_events(el);\n",
       "    }\n",
       "\n",
       "}\n",
       "\n",
       "mpl.figure.prototype._key_event_extra = function(event, name) {\n",
       "    var manager = IPython.notebook.keyboard_manager;\n",
       "    if (!manager)\n",
       "        manager = IPython.keyboard_manager;\n",
       "\n",
       "    // Check for shift+enter\n",
       "    if (event.shiftKey && event.which == 13) {\n",
       "        this.canvas_div.blur();\n",
       "        event.shiftKey = false;\n",
       "        // Send a \"J\" for go to next cell\n",
       "        event.which = 74;\n",
       "        event.keyCode = 74;\n",
       "        manager.command_mode();\n",
       "        manager.handle_keydown(event);\n",
       "    }\n",
       "}\n",
       "\n",
       "mpl.figure.prototype.handle_save = function(fig, msg) {\n",
       "    fig.ondownload(fig, null);\n",
       "}\n",
       "\n",
       "\n",
       "mpl.find_output_cell = function(html_output) {\n",
       "    // Return the cell and output element which can be found *uniquely* in the notebook.\n",
       "    // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
       "    // IPython event is triggered only after the cells have been serialised, which for\n",
       "    // our purposes (turning an active figure into a static one), is too late.\n",
       "    var cells = IPython.notebook.get_cells();\n",
       "    var ncells = cells.length;\n",
       "    for (var i=0; i<ncells; i++) {\n",
       "        var cell = cells[i];\n",
       "        if (cell.cell_type === 'code'){\n",
       "            for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
       "                var data = cell.output_area.outputs[j];\n",
       "                if (data.data) {\n",
       "                    // IPython >= 3 moved mimebundle to data attribute of output\n",
       "                    data = data.data;\n",
       "                }\n",
       "                if (data['text/html'] == html_output) {\n",
       "                    return [cell, data, j];\n",
       "                }\n",
       "            }\n",
       "        }\n",
       "    }\n",
       "}\n",
       "\n",
       "// Register the function which deals with the matplotlib target/channel.\n",
       "// The kernel may be null if the page has been refreshed.\n",
       "if (IPython.notebook.kernel != null) {\n",
       "    IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
       "}\n"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<img src=\"\" width=\"1079.4666666666667\">"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Initial the plot \n",
    "fig = plt.figure(figsize=(15, 12))\n",
    "gs = GridSpec(2, 16, figure=fig)\n",
    "# Distribute the subplots\n",
    "pie_ax = fig.add_subplot(gs[0, :8])\n",
    "pie_select_ax = fig.add_subplot(gs[0, -8:])\n",
    "bar_ax = fig.add_subplot(gs[1, :-3])\n",
    "bar_select_ax = fig.add_subplot(gs[1, -3:])\n",
    "\n",
    "# Draw the pie plot\n",
    "pie_props = {\n",
    "    'ax': pie_ax,\n",
    "    'labels': pie_labels,\n",
    "    'data': pie_data,\n",
    "    'is_pie': True,\n",
    "    'title': \"the disease groups as side effects in drug interaction with |{}|\",\n",
    "    'font_dicts': None,\n",
    "    'colors': cm.Blues(np.arange(len(pie_labels)) / len(pie_labels) + 0.2)\n",
    "}\n",
    "pie = SelectionPlot(**pie_props)\n",
    "pie_sb = SelectionBox(ax=pie_select_ax,\n",
    "                      labels=pie_data.index,\n",
    "                      active=len(pie_data.index) - 1,\n",
    "                      activecolor='#274279')\n",
    "pie_sb.set_buttons(circleprops={'fc': 'white', 'ec': '#274279'})\n",
    "pie_sb.on_clicked(pie.draw)\n",
    "\n",
    "# Draw the bar plot\n",
    "bar_props = {\n",
    "    'ax': bar_ax,\n",
    "    'labels': bar_labels,\n",
    "    'data': bar_data,\n",
    "    'is_pie': False,\n",
    "    'title': \"The number of drugs causing |{}| in drug interaction\",\n",
    "    'font_dicts': None,\n",
    "    'width': 0.3\n",
    "}\n",
    "bar = SelectionPlot(**bar_props)\n",
    "bar_sb = SelectionBox(ax=bar_select_ax,\n",
    "                      labels=bar_data.columns,\n",
    "                      active=len(bar_data.columns) - 1,\n",
    "                      activecolor='#274279')\n",
    "bar_sb.set_buttons(circleprops={'fc': 'white', 'ec': '#274279'})\n",
    "bar_sb.on_clicked(bar.draw)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
